/*
* This file is a part of the open-eBackup project.
* This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
* If a copy of the MPL was not distributed with this file, You can obtain one at
* http://mozilla.org/MPL/2.0/.
*
* Copyright (c) [2024] Huawei Technologies Co.,Ltd.
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
*/
#include "OceanStorVolumeHandler.h"
#include <boost/uuid/uuid_io.hpp>
#include "common/Structs.h"
#include "common/utils/Utils.h"
#include "volume_handlers/common/DiskDeviceFile.h"
#include "volume_handlers/common/DiskCommDef.h"
#include "ApiOperatorManager.h"
#include "DiskScannerHandler.h"

namespace {
constexpr int32_t RETURN_NOT_EXIST = -3;
const std::string FULL_BACKUP = "HCP_FULL_SNAPSHOT";
const std::string MODULE_NAME = "DoradoV6Disk";
const uint64_t SNAPSHOT_BEYOND_LUN_INVALID = 348348421;
const int32_t BITMAP_SPLIT = 2;
const int32_t BASE_URL_SPLIT = 2;
const int32_t BITMAP_BY_BYTE = 8;
const int32_t BITMAP_REQ_SIZE = 4 * 1024 * 8;
const int32_t RETRY_TIMES = 60;
const int32_t RESCAN_WAIT_TIME = 30;  // seconds
const int32_t ORIGIN_TIMEOUT = 15;
const int32_t NO_STORAGE_INFO = 1577213586;
}

namespace VirtPlugin {
OceanStorVolumeHandler::OceanStorVolumeHandler(std::shared_ptr<JobHandle> jobHandle, const VolInfo &volInfo,
    std::string jobId, std::string subJobId)
    : VolumeHandler(jobHandle, volInfo, jobId, subJobId)
{
    if (m_jobHandle != nullptr) {
        m_backupType = m_jobHandle->GetBackupType();
    }
}

/**
 *  @brief 初始化VolumeHandler
 *
 *  @return 成功返回 SUCCESS，出错返回 Module::FAILED
 */
int32_t OceanStorVolumeHandler::InitializeVolumeInfo()
{
    if (m_jobHandle == nullptr) {
        ERRLOG("Job handle is null.");
        return Module::FAILED;
    }
    m_isBackup = m_jobHandle->GetJobType() == JobType::BACKUP;
    int32_t erro = 0;
    if (GetStorageInfo(erro) != Module::SUCCESS) {
        ERRLOG("Get storage info failed, %d.", erro);
        return Module::FAILED;
    }
    m_spApiOperator->InitHttpConfig();
    if (!Module::JsonHelper::JsonStringToStruct(m_volInfo.m_datastore.m_extendInfo, m_dsExtend)) {
        ERRLOG("Trans datastore extend to struct failed. Extend: %s",
            WIPE_SENSITIVE(m_volInfo.m_datastore.m_extendInfo).c_str());
        return Module::FAILED;
    }

    std::string lunId = m_dsExtend.m_volId;
    LunMO lunMo;
    std::string errorDes;
    int32_t ret = m_spApiOperator->GetLunByID(lunId, lunMo, errorDes);
    if (ret != Module::SUCCESS) {
        ERRLOG("Get lun by id failed, errorDes:%s", errorDes.c_str());
        return Module::FAILED;
    }
    m_diskCapacityInBytes = lunMo.m_capacity;
    m_spDeviceFile = std::make_shared<DiskDeviceFile>();
    if (m_spDeviceFile.get() == nullptr) {
        ERRLOG("Create DiskDeviceFile failed.");
        return Module::FAILED;
    }
    return Module::SUCCESS;
}

int32_t OceanStorVolumeHandler::GetStorageInfo(int32_t &erro)
{
    if (m_volInfo.m_datastore.m_moRef.empty()) {
        ERRLOG("Get volume sn failed.");
        return Module::FAILED;
    }
    std::string extendInfo = m_jobHandle->GetAppEnv().auth.extendInfo;
    if (extendInfo.empty()) {
        ERRLOG("Extend info is empty!");
        return Module::FAILED;
    }
    return GetStorageInfoFromAppEnvAuth(extendInfo, erro);
}

int32_t OceanStorVolumeHandler::GetStorageInfoFromAppEnvAuth(const std::string &extendInfo, int32_t &erro)
{
    Storages storages;
    Module::JsonHelper::JsonStringToStruct(extendInfo, storages);
    Json::Value storageValue;
    Module::JsonHelper::JsonStringToJsonValue(storages.m_storages, storageValue);
    std::vector<StorageInfo> storageVector = {};
    for (const auto &item: storageValue) {
        StorageInfo storageInfo;
        Module::JsonHelper::JsonStringToStruct(item.toStyledString(), storageInfo);
        storageVector.push_back(storageInfo);
    }
    ControlDeviceInfo deviceInfo {};
    for (auto &item : storageVector) {
        INFOLOG("item.m_sn:%s, item.m_ip:%s, item.m_port:%d", item.m_sn.c_str(), item.m_ip.c_str(), item.m_port);
        if (item.m_sn == m_volInfo.m_datastore.m_moRef) {
            if (InitControlDeviceInfo(deviceInfo, item) != Module::SUCCESS) {
                ERRLOG("Init control device info failed.");
                return Module::FAILED;
            }
            break;
        }
    }
    if (deviceInfo.m_ip.empty() || deviceInfo.m_port.empty() || deviceInfo.m_userName.empty() ||
        deviceInfo.m_password.empty() || deviceInfo.m_storageType.empty()) {
        ERRLOG("Get device info failed, ip:%s, port:%s, type:%s", deviceInfo.m_ip.c_str(),
            deviceInfo.m_port.c_str(), deviceInfo.m_storageType.c_str());
        erro = NO_STORAGE_INFO;
        return Module::FAILED;
    }
    deviceInfo.m_storageType = m_volInfo.m_datastore.m_type;
    deviceInfo.m_poolId = m_volInfo.m_datastore.mPoolIdInt;
    if (ApiOperatorManager::GetInstance()->GetRestApiOperator(deviceInfo, m_spApiOperator, true, m_isOpService)
        != Module::SUCCESS) {
        ERRLOG("Get rest api operator failed.");
        return Module::FAILED;
    }
    return Module::SUCCESS;
}

int32_t OceanStorVolumeHandler::InitControlDeviceInfo(ControlDeviceInfo &deviceInfo, StorageInfo &storageInfo)
{
    deviceInfo.m_ip = storageInfo.m_ip;
    deviceInfo.m_port = std::to_string(storageInfo.m_port);
    deviceInfo.m_userName = storageInfo.m_userName;
    deviceInfo.m_password = storageInfo.m_passWd;
    Utils::GetIpVectorFromString(deviceInfo.m_ipList, deviceInfo.m_ip, storageInfo.m_ipList);
    deviceInfo.m_storageType = m_volInfo.m_datastore.m_type;
    deviceInfo.m_enableCert = (storageInfo.m_enableCert == "1") ? true : false;
    std::string storageInfoStr;
    if (!Module::JsonHelper::StructToJsonString(storageInfo, storageInfoStr)) {
        ERRLOG("Convert storageInfo to json string failed.");
        return Module::FAILED;
    }
    CertManger storageCertMgr;
    CertInfo cert;
    if (!storageCertMgr.ParseCert(storageInfo.m_ip, storageInfoStr, cert)) {
        ERRLOG("Parse storage cert info failed.");
        return Module::FAILED;
    }
    if (deviceInfo.m_enableCert) {
        deviceInfo.m_cert = storageCertMgr.GetSpecifyCerPath(storageInfo.m_ip);
    }
    if (!storageInfo.m_revocationList.empty()) {
        deviceInfo.m_revocationList = storageCertMgr.GetSpecifyRclPath(storageInfo.m_ip);
    }
    return Module::SUCCESS;
}

int32_t OceanStorVolumeHandler::TestDeviceConnection(const std::string &authExtendInfo, int32_t &erroCode)
{
    if (GetStorageInfoFromAppEnvAuth(authExtendInfo, erroCode) != Module::SUCCESS) {
        ERRLOG("Get storage info from app env auth failed.");
        return Module::FAILED;
    }
    return m_spApiOperator->TestDeviceConnection();
}

/**
 *  @brief 打开块设备（备份场景）
 *
 *  @param VolOpenMode   [IN] 模式
 *  @param VolSnapInfo   [IN] 快照
 *  @return 成功返回 SUCCESS，出错返回 Module::FAILED
 */
int32_t OceanStorVolumeHandler::Open(const VolOpenMode &mode, const BackupSubJobInfo &jobInfo)
{
    VolSnapInfo snapshot = jobInfo.m_curSnapshotInfo;
    INFOLOG("Start to open disk for backup!");
    if (m_spApiOperator == nullptr) {
        ERRLOG("Open volume file failed! spApiOperator is empty.");
        return Module::FAILED;
    }
    DBGLOG("Snapshot id: %s", snapshot.m_storageSnapId.c_str());
    m_snapshotId = snapshot.m_storageSnapId;
    SnapshotMO snapshotMO;
    std::string errorDes;
    int32_t ret = m_spApiOperator->GetSnapShotByID(m_snapshotId, snapshotMO, errorDes);
    TP_START("TP_OceanStorageOpenForBakFailed", 1, &ret);
    TP_END
    if (ret != Module::SUCCESS) {
        ERRLOG("Get snapshot by id failed, errorDes:%s", errorDes);
        return Module::FAILED;
    }
    INFOLOG("Get snapshot success, wwn:%s", snapshotMO.m_wwn.c_str());
    m_curChangeObj.m_id = snapshotMO.m_id;
    m_curChangeObj.m_name = snapshotMO.m_name;
    m_curChangeObj.m_wwn = snapshotMO.m_wwn;
    m_spApiOperator->SetDiskName(snapshotMO.m_name);
    INFOLOG("Open disk objId:%s", snapshotMO.m_id.c_str());
    ret = m_spApiOperator->CreateMappingSet(m_snapshotId, MO_SNAPSHOT);
    if (ret != Module::SUCCESS) {
        ERRLOG("Init mapping set failed.");
        m_spApiOperator->DeleteMappingSet(m_snapshotId, MO_SNAPSHOT);
        return Module::FAILED;
    }
    std::string devicePath;
    if (DoScanDisk(snapshotMO.m_id, snapshotMO.m_wwn, devicePath) != Module::SUCCESS) {
        ERRLOG("Scan snapshot failed, snapshot id:%s, wwn:%s", snapshotMO.m_id.c_str(), snapshotMO.m_wwn.c_str());
        m_spApiOperator->DeleteMappingSet(m_snapshotId, MO_SNAPSHOT);
        return Module::FAILED;
    }
    m_devicePath = devicePath;
    if (m_spDeviceFile.get() == nullptr) {
        ERRLOG("Disk device file is empty.");
        return Module::FAILED;
    }
    int32_t owMode = (mode == VolOpenMode::READ_WRITE) ? O_WRONLY : O_RDONLY;
    DiskScannerHandler::GetInstance()->ChangeFilePriviledge(m_devicePath, mode);
    if (m_spDeviceFile->Open(devicePath, owMode, snapshotMO.m_userCapacity) != DISK_DEVICE_OK) {
        ERRLOG("Open volume file failed ! path is %s", devicePath.c_str());
        m_spApiOperator->DeleteMappingSet(m_snapshotId, MO_SNAPSHOT);
        return Module::FAILED;
    }
    return Module::SUCCESS;
}

/**
 *  @brief 打开块设备（恢复场景）
 *
 *  @param VolOpenMode   [IN] 模式
 *  @return 成功返回 SUCCESS，出错返回 Module::FAILED
 */
int32_t OceanStorVolumeHandler::Open(const VolOpenMode &mode)
{
    INFOLOG("Start to open disk for restore!");
    if (m_spApiOperator == nullptr) {
        ERRLOG("Open volume file failed! spApiOperator is empty.");
        return Module::FAILED;
    }

    m_lunId = m_dsExtend.m_volId;
    LunMO lunMo;
    std::string errorDes;
    int32_t ret = m_spApiOperator->GetLunByID(m_lunId, lunMo, errorDes);
    if (ret != Module::SUCCESS) {
        ERRLOG("Get lun by id failed, errorDes:%s", errorDes);
        return Module::FAILED;
    }
    if (!m_dsExtend.m_volId.empty() && m_dsExtend.m_volWwn != lunMo.m_wwn) {
        ERRLOG("Lun wwn:%s not match: %s", m_dsExtend.m_volWwn.c_str(), lunMo.m_wwn.c_str());
        return Module::FAILED;
    }
    m_curChangeObj.m_id = m_dsExtend.m_volId;
    m_curChangeObj.m_name = m_dsExtend.m_volName;
    m_curChangeObj.m_wwn = m_dsExtend.m_volWwn;
    m_spApiOperator->SetDiskName(lunMo.m_name);
    ret = m_spApiOperator->CreateMappingSet(m_lunId, MO_LUN);
    if (ret != Module::SUCCESS) {
        ERRLOG("Init mapping set failed.");
        m_spApiOperator->DeleteMappingSet(m_lunId, MO_LUN);
        return Module::FAILED;
    }
    if (DoScanDisk(lunMo.m_id, lunMo.m_wwn, m_devicePath) != Module::SUCCESS) {
        ERRLOG("Scan lun failed, lun id:%s, wwn: %s.", lunMo.m_id.c_str(), lunMo.m_wwn.c_str());
        m_spApiOperator->DeleteMappingSet(m_lunId, MO_LUN);
        return Module::FAILED;
    }
    if (m_spDeviceFile.get() == nullptr) {
        ERRLOG("Disk device file is empty.");
        return Module::FAILED;
    }
    DiskScannerHandler::GetInstance()->ChangeFilePriviledge(m_devicePath, mode);
    int32_t owMode = (mode == VolOpenMode::READ_WRITE) ? O_WRONLY : O_RDONLY;
    if (m_spDeviceFile->Open(m_devicePath, owMode, lunMo.m_capacity) != DISK_DEVICE_OK) {
        ERRLOG("Open volume file failed ! path is %s", m_devicePath.c_str());
        m_spApiOperator->DeleteMappingSet(m_lunId, MO_LUN);
        return Module::FAILED;
    }
    return Module::SUCCESS;
}

int32_t OceanStorVolumeHandler::DoScanDisk(const std::string &objId, const std::string &objWwn, std::string &objPath)
{
    int retryTimes = 0;
    while (retryTimes < RETRY_TIMES) {
        int32_t ret = DiskScannerHandler::GetInstance()->DoScanAfterAttach(objId, objWwn, objPath,
            m_spApiOperator->GetUseIscsi());
        if (ret == Module::SUCCESS) {
            return ret;
        }
        if (retryTimes > 0) {
            WARNLOG("Retry to scan disk, retry times:%d, wwn:%s", retryTimes, objWwn.c_str());
            std::this_thread::sleep_for(std::chrono::seconds(RESCAN_WAIT_TIME));
        }
        ++retryTimes;
    }
    return Module::FAILED;
}

/**
 *  @brief 关闭块设备
 *
 *  @return 成功返回 SUCCESS，出错返回 Module::FAILED
 */
int32_t OceanStorVolumeHandler::Close()
{
    INFOLOG("Close disk for %s", (m_isBackup ? "Backup" : "Restore"));
    int32_t iRet = Module::SUCCESS;
    std::string errorDes("Internal error!");
    if (m_spDeviceFile.get() == nullptr) {
        iRet = Module::FAILED;
        ERRLOG("Disk device file is empty.");
    } else {
        if (m_spDeviceFile->Close() != DISK_DEVICE_OK) {
            iRet = Module::FAILED;
            errorDes = m_spDeviceFile->GetErrString();
            ERRLOG("Close volume file failed, errorDes:%s", errorDes.c_str());
        }
    }
    MO_TYPE objType = m_isBackup ? MO_SNAPSHOT : MO_LUN;
    std::string objId = m_isBackup ? m_snapshotId : m_lunId;
    INFOLOG("Start to close disk , id:%s, wwn:%s", m_curChangeObj.m_id.c_str(), m_curChangeObj.m_wwn.c_str());
    if (DiskScannerHandler::GetInstance()->DetachVolume(m_curChangeObj.m_id, m_curChangeObj.m_wwn) != Module::SUCCESS) {
        iRet = Module::FAILED;
        ERRLOG("Detach volume failed!");
    }
    if (m_spApiOperator->DeleteMappingSet(objId, objType) != Module::SUCCESS) {
        iRet = Module::FAILED;
        ERRLOG("Delete mapping set failed");
    }
    return iRet;
}

/**
 *  @brief 从块设备读取数据
 *
 *  @param offsetInBytes        [IN] 起始地址
 *  @param bufferSizeInBytes    [IN] 数据量大小
 *  @param buffer               [OUT] 数据存放buffer
 *  @return 成功返回 SUCCESS，出错返回 Module::FAILED
 */
int32_t OceanStorVolumeHandler::ReadBlocks(const uint64_t& offsetInBytes, uint64_t& bufferSizeInBytes,
    std::shared_ptr<uint8_t[]> &buffer, std::shared_ptr<uint8_t[]> &calBuffer, std::shared_ptr<uint8_t[]> &readBuffer)
{
    int32_t ret = Module::SUCCESS;
    TP_START("TP_OceanStorageReadFailed", 1, &ret);
    TP_END
    if (ret == Module::FAILED) {
        return Module::FAILED;
    }
    if (m_spDeviceFile.get() == nullptr) {
        ERRLOG("Disk device file is empty.");
        return Module::FAILED;
    }
    if (m_spDeviceFile->Read(offsetInBytes, bufferSizeInBytes, buffer) != DISK_DEVICE_OK) {
        ERRLOG("Read volume block failed, err desc:%s", m_spDeviceFile->GetErrString().c_str());
        return Module::FAILED;
    }
    m_spDeviceFile->ReleaseBufferCache(offsetInBytes, bufferSizeInBytes);
    if (m_backupType == AppProtect::BackupJobType::FULL_BACKUP) {
        if (memcmp(buffer.get(), GetAllZeroDirtyRangeDataPtr().get(), DIRTY_RANGE_BLOCK_SIZE) == 0) {
            return DATA_ALL_ZERO_IGNORE_WRITE;
        }
    }
    return Module::SUCCESS;
}

/**
 *  @brief 写数据到块设备
 *
 *  @param offsetInBytes        [IN] 起始地址
 *  @param bufferSizeInBytes    [IN] 数据量大小
 *  @param buffer               [OUT] 数据存放buffer
 *  @return 成功返回 SUCCESS，出错返回 Module::FAILED
 */
int32_t OceanStorVolumeHandler::WriteBlocks(const uint64_t& offsetInBytes, uint64_t& bufferSizeInBytes,
    std::shared_ptr<uint8_t[]> &buffer)
{
    int32_t ret = Module::SUCCESS;
    TP_START("TP_OceanStorageWriteFailed", 1, &ret);
    TP_END
    if (ret == Module::FAILED) {
        return Module::FAILED;
    }
    if (m_spDeviceFile.get() == nullptr) {
        ERRLOG("Disk device file is empty.");
        return Module::FAILED;
    }
    if (m_spDeviceFile->Write(offsetInBytes, bufferSizeInBytes, buffer) != DISK_DEVICE_OK) {
        ERRLOG("Write volume block failed, err desc:%s", m_spDeviceFile->GetErrString().c_str());
        return Module::FAILED;
    }
    return Module::SUCCESS;
}

/**
 *  @brief 获取卷特定块的增量位置信息
 *
 *  @param preVolSnapshot [IN]上一次CBT或快照ID
 *  @param curVolSnapshot [IN]当前快照信息
 *  @param dirtyRanges    [IN,OUT]该卷的增量位置信息
 *  @param startOffset    [IN]块的起始位置
 *  @param endOffset      [IN]块的结束位置
 *  @return 成功返回 SUCCESS，出错返回 Module::FAILED
 */
int32_t OceanStorVolumeHandler::GetDirtyRanges(const VolSnapInfo &preVolSnapshot, const VolSnapInfo &curVolSnapshot,
    DirtyRanges &dirtyRanges, const uint64_t startOffset, uint64_t &endOffset)
{
    dirtyRanges.clear();
    if (m_spApiOperator == nullptr) {
        ERRLOG("Get dirty ranges failed! ApiOperator not initialize.");
        return Module::FAILED;
    }
    int32_t iRet = Module::SUCCESS;
    iRet = SetChangeInfo(preVolSnapshot, curVolSnapshot);
    if (iRet != Module::SUCCESS) {
        ERRLOG("Set change info failed.");
        return iRet;
    }
    dirtyRanges.clear();
    std::string errorDes("Internal error!");
    iRet = m_spApiOperator->GetLunChunkSize(m_curChangeObj.m_id, m_chunkSize, errorDes);
    if (iRet != Module::SUCCESS) {
        ERRLOG("Get lun chunk size failed, error des:%s", errorDes.c_str());
        return iRet;
    }
    DBGLOG("Get lun chunk size:%lld", m_chunkSize);
    iRet = ExecGetDirtyRanges(dirtyRanges, startOffset, endOffset);
    if (iRet != Module::SUCCESS) {
        ERRLOG("Exec get dirty ranges failed.");
        return iRet;
    }
    bool bAlarm = !preVolSnapshot.m_storageSnapId.empty() && m_preChangeObj.m_isFullBackup && m_isBackup;
    if (bAlarm) {
        WARNLOG("Set pre-change id alarm.");
    }
    return iRet;
}

int32_t OceanStorVolumeHandler::SetChangeInfo(const VolSnapInfo &preVolSnapshot, const VolSnapInfo &curVolSnapshot)
{
    std::string errorDes("Internal error!");
    if (m_isBackup) {
        SnapshotMO snapshotMO;
        int32_t ret = m_spApiOperator->GetSnapShotByID(curVolSnapshot.m_storageSnapId, snapshotMO, errorDes);
        if (ret != Module::SUCCESS) {
            ERRLOG("Get curSnapshot info failed, id:%s", curVolSnapshot.m_storageSnapId.c_str());
            return Module::FAILED;
        }
        m_curChangeObj.m_id = snapshotMO.m_id;
        m_curChangeObj.m_name = snapshotMO.m_name;
        m_curChangeObj.m_wwn = snapshotMO.m_wwn;
    } else {
        m_curChangeObj.m_id = m_dsExtend.m_volId;
        m_curChangeObj.m_name = m_dsExtend.m_volName;
        m_curChangeObj.m_wwn = m_dsExtend.m_volWwn;
    }
    DBGLOG("Cur change id:%s, name:%s, wwn:%s", m_curChangeObj.m_id.c_str(), m_curChangeObj.m_name.c_str(),
        m_curChangeObj.m_wwn.c_str());
    if (preVolSnapshot.m_storageSnapId.empty() || preVolSnapshot.m_storageSnapId == FULL_BACKUP) {
        // 前一次快照为空或者为FULL_BACKUP 直接全量
        WARNLOG("Pre snapshot is empty, id:%s", preVolSnapshot.m_storageSnapId.c_str());
        m_preChangeObj.m_isFullBackup = true;
    }
    if (!preVolSnapshot.m_storageSnapId.empty() && preVolSnapshot.m_storageSnapId != FULL_BACKUP) {
        SnapshotMO snapshotMO;
        int32_t ret = m_spApiOperator->GetSnapShotByID(preVolSnapshot.m_storageSnapId, snapshotMO, errorDes);
        // 如果上一次快照已经被删除则直接做全量
        if (ret == ApiErrorCode::SNAPSHOT_NOTEXIST) {
            WARNLOG("Pre snapshot not exits, id:%s", preVolSnapshot.m_storageSnapId.c_str());
            m_preChangeObj.m_isFullBackup = true;
        } else if (ret != Module::SUCCESS) {
            ERRLOG("Get preSnapshot info failed, id:%s, error des:%s", preVolSnapshot.m_storageSnapId.c_str(),
                errorDes.c_str());
            return Module::FAILED;
        }
        // 如果上次快照的wwn与上次备份时记录下来的wwn不匹配，则上面前一次快照已经被删除，直接转全量
        if (preVolSnapshot.m_volUuid != snapshotMO.m_wwn) {
            WARNLOG("Pre snapshot wwn is invalid, preSnapshot wwn:%s, current wwn:%s",
                preVolSnapshot.m_volUuid.c_str(), snapshotMO.m_wwn.c_str());
        }
        m_preChangeObj.m_id = snapshotMO.m_id;
        m_preChangeObj.m_name = snapshotMO.m_name;
        m_preChangeObj.m_wwn = snapshotMO.m_wwn;
        DBGLOG("Pre change id:%s, name:%s, wwn:%s", m_preChangeObj.m_id.c_str(), m_preChangeObj.m_name.c_str(),
            m_preChangeObj.m_wwn.c_str());
    }
    return Module::SUCCESS;
}

int32_t OceanStorVolumeHandler::ExecGetDirtyRanges(DirtyRanges& dirtyRanges, const uint64_t &startOffset,
    const uint64_t &endOffset)
{
    // 如果是全量恢复则没必要再去请求差量信息。即使是thin
    // lun也没比要，因为在做备份的时候只备份了已分配数据，对于没有分配的数据，恢复的时候会忽略
    bool bFullRestore = (!m_isBackup) && m_preChangeObj.m_isFullBackup;
    if (bFullRestore) {
        dirtyRanges.UseFull();
        DirtyRange everything(startOffset, endOffset - startOffset);
        // 首次调用AddRange，AddRange函数不会返回失败。此处无需判断返回值。
        (void) dirtyRanges.AddRange(everything);
        DBGLOG("It do not need get allocate bitmap for full restore.");
        return Module::SUCCESS;
    }
    DBGLOG("Previous change id is %s", m_preChangeObj.m_id.c_str());
    std::string errorDes("Internal error!");
    // 全量备份、增量备份、增量恢复
    int32_t iRet = GetDirtyRangesFragmentForLun(startOffset, endOffset, dirtyRanges, errorDes);
    if (iRet != Module::SUCCESS) {
        ERRLOG("Get diryranges segment failed, des:%s", errorDes.c_str());
        return iRet;
    }
    return Module::SUCCESS;
}

int32_t OceanStorVolumeHandler::GetDirtyRangesFragmentForLun(const uint64_t &startOffset, const uint64_t &endOffset,
    DirtyRanges& dirtyRanges, std::string& errorDes)
{
    DirtyRangesRequest dirtyRangesRequest;
    dirtyRangesRequest.m_preChangeObj = m_preChangeObj;
    dirtyRangesRequest.m_curChangeObj = m_curChangeObj;
    dirtyRangesRequest.m_startOffset = startOffset;
    dirtyRangesRequest.m_endOffset = endOffset;
    dirtyRangesRequest.m_lunCapacity = m_diskCapacityInBytes;
    if (PrepareDirtyRangesFragmentForLun(dirtyRangesRequest, errorDes) != Module::SUCCESS) {
        ERRLOG("Prepare dirty ranges fragment for lun failed, preChange=%s, change=%s %lld %lld",
            m_preChangeObj.m_id.c_str(), m_curChangeObj.m_id.c_str(), startOffset, endOffset);
        return Module::FAILED;
    }
    if (GetDirtyRangesFragmentForLunImp(dirtyRangesRequest, dirtyRanges, errorDes) != Module::SUCCESS) {
        ERRLOG("Get dirty ranges fragment for lun imp failed, preChange=%s, change=%s %lld %lld",
            m_preChangeObj.m_id.c_str(), m_curChangeObj.m_id.c_str(), startOffset, endOffset);
        return Module::FAILED;
    }
    return Module::SUCCESS;
}

int32_t OceanStorVolumeHandler::PrepareDirtyRangesFragmentForLun(DirtyRangesRequest& dirtyRangesRequest,
    std::string& errorDes)
{
    uint64_t preChangeCapacity = 0;
    uint64_t curChangeCapacity = 0;
    if (GetSnapshotCapacity(dirtyRangesRequest.m_preChangeObj, preChangeCapacity, errorDes) != Module::SUCCESS) {
        ERRLOG("Get pre-snapshot capacity failed, id:%s", dirtyRangesRequest.m_preChangeObj.m_id.c_str());
        return Module::FAILED;
    }
    if (m_isBackup) {
        if (GetSnapshotCapacity(dirtyRangesRequest.m_curChangeObj, curChangeCapacity, errorDes) != Module::SUCCESS) {
            ERRLOG("Get cur-snapshot capacity failed, id:%s", dirtyRangesRequest.m_curChangeObj.m_id.c_str());
            return Module::FAILED;
        }
    } else {
        curChangeCapacity = m_diskCapacityInBytes;
    }
    dirtyRangesRequest.m_endOffset = curChangeCapacity < dirtyRangesRequest.m_endOffset ? curChangeCapacity :
        dirtyRangesRequest.m_endOffset;
    dirtyRangesRequest.m_changeCapacity = curChangeCapacity;
    dirtyRangesRequest.m_preChangeCapacity = preChangeCapacity;
    if (!CheckDirtyRangesRequest(dirtyRangesRequest)) {
        ERRLOG("Check dirty ranges request failed.");
        return Module::FAILED;
    }
    DBGLOG("Cur change id : %s, pre change id: %s, start offset: %lld, end offset: %lld, , chunk size: %lld,\
        pre capacity: %lld, cur capacity: %lld, disk size=%lld", dirtyRangesRequest.m_curChangeObj.m_id.c_str(),
        dirtyRangesRequest.m_preChangeObj.m_id.c_str(), dirtyRangesRequest.m_startOffset,
        dirtyRangesRequest.m_endOffset, m_chunkSize, preChangeCapacity, curChangeCapacity,
        dirtyRangesRequest.m_lunCapacity);
    if (CheckExpansion(dirtyRangesRequest) != Module::SUCCESS) {
        ERRLOG("Check expansion failed.");
        return Module::FAILED;
    }
    if (!CheckDirtyRangesRequest(dirtyRangesRequest)) {
        ERRLOG("Check dirty ranges request failed.");
        return Module::FAILED;
    }
    DBGLOG("Disk size: %lld, overlap size: %lld, standalone offset: %lld, standalone size: %lld",
        dirtyRangesRequest.m_lunCapacity, dirtyRangesRequest.m_overlapSize,
        dirtyRangesRequest.m_standaloneOffset, dirtyRangesRequest.m_standaloneSize);
    return Module::SUCCESS;
}

int32_t OceanStorVolumeHandler::GetSnapshotCapacity(const NativeObjectInfo& snapshotObj, uint64_t& capacity,
    std::string& errDes)
{
    if (snapshotObj.m_isFullBackup) {
        capacity = 0;
        return Module::SUCCESS;
    }
    SnapshotMO snapshotMO;
    if (m_spApiOperator->GetSnapShotByID(snapshotObj.m_id, snapshotMO, errDes) != Module::SUCCESS) {
        ERRLOG("Get snapshot failed, id:%s", snapshotObj.m_id.c_str());
        return Module::FAILED;
    }
    capacity = snapshotMO.m_userCapacity;
    return Module::SUCCESS;
}

int32_t OceanStorVolumeHandler::CheckExpansion(DirtyRangesRequest& dirtyRangesRequest)
{
    uint64_t preChangeCapacity = dirtyRangesRequest.m_preChangeCapacity;
    uint64_t changeCapacity = dirtyRangesRequest.m_changeCapacity;
    uint64_t startOffset = dirtyRangesRequest.m_startOffset;
    uint64_t endOffset = dirtyRangesRequest.m_endOffset;
    uint64_t& overlapSize = dirtyRangesRequest.m_overlapSize;
    uint64_t& standaloneOffset = dirtyRangesRequest.m_standaloneOffset;
    uint64_t& standaloneSize = dirtyRangesRequest.m_standaloneSize;
    if (preChangeCapacity > changeCapacity) {
        ERRLOG("Param invalid.%lld %lld", preChangeCapacity, changeCapacity);
        return Module::FAILED;
    }
    // [startOffset,endOffset] in set of preChange intersect with Change
    if (preChangeCapacity == changeCapacity) {
        // we have not expanded the lun capacity after last backup
        overlapSize = endOffset - startOffset;
        standaloneOffset = endOffset;
        standaloneSize = 0;
        return Module::SUCCESS;
    }
    // preChangeCapacity < changeCapacity
    // we have expanded the lun capacity after last backup
    // [startOffset,endOffset] in set of preChange  intersect with Change
    if (preChangeCapacity >= endOffset) {
        overlapSize = endOffset - startOffset;
        standaloneOffset = endOffset;
        standaloneSize = 0;
        return Module::SUCCESS;
    }
    // [startOffset,endOffset] in set of (change - preChange)
    if (startOffset >= preChangeCapacity) {
        overlapSize = 0;
        standaloneOffset = startOffset;
        standaloneSize = endOffset - startOffset;
        return Module::SUCCESS;
    }
    // startOffset <  preChangeCapacity  < endOffset
    standaloneOffset = ((preChangeCapacity) / m_chunkSize) * m_chunkSize;
    standaloneSize = endOffset - standaloneOffset;
    overlapSize = standaloneOffset - startOffset;
    bool bCheck = ((startOffset % m_chunkSize) == 0) && (startOffset <= standaloneOffset) &&
        (standaloneOffset % m_chunkSize) == 0 && (standaloneOffset <= preChangeCapacity);
    if (!bCheck) {
        ERRLOG("Param invalid.%lld %lld %lld %lld", startOffset, m_chunkSize, standaloneOffset, preChangeCapacity);
        return Module::FAILED;
    }
    return Module::SUCCESS;
}

bool OceanStorVolumeHandler::CheckDirtyRangesRequest(const DirtyRangesRequest& dirtyRangesRequest)
{
    uint64_t startOffset = dirtyRangesRequest.m_startOffset;
    uint64_t endOffset = dirtyRangesRequest.m_endOffset;
    uint64_t changeCapacity = dirtyRangesRequest.m_changeCapacity;
    uint64_t preChangeCapacity = dirtyRangesRequest.m_preChangeCapacity;
    uint64_t overlapSize = dirtyRangesRequest.m_overlapSize;
    uint64_t standaloneOffset = dirtyRangesRequest.m_standaloneOffset;
    uint64_t standaloneSize = dirtyRangesRequest.m_standaloneSize;
    uint64_t lunCapacity = dirtyRangesRequest.m_lunCapacity;
    if (changeCapacity > 0) {
        bool beFull = dirtyRangesRequest.m_preChangeObj.m_isFullBackup;
        bool bCheck = (preChangeCapacity <= changeCapacity) && (endOffset <= changeCapacity) &&
            (changeCapacity <= lunCapacity) && (changeCapacity > 0) && (lunCapacity > 0) &&
            (beFull ? (preChangeCapacity == 0) : (preChangeCapacity > 0)) && ((startOffset % m_chunkSize) == 0);
        if (!bCheck) {
            ERRLOG("capacity invalid. %lld %lld %lld %lld, preChange=%s , change=%s %lld %lld",
                preChangeCapacity, changeCapacity, lunCapacity, endOffset,
                dirtyRangesRequest.m_preChangeObj.m_id.c_str(), dirtyRangesRequest.m_curChangeObj.m_id.c_str(),
                startOffset, m_chunkSize);
            return false;
        }
    }
    if (overlapSize > 0 || standaloneSize > 0) {
        bool bCheck = ((startOffset + overlapSize) == standaloneOffset) &&
            ((standaloneOffset + standaloneSize) == endOffset) &&
            ((overlapSize > 0 && standaloneSize > 0) ? ((standaloneOffset % m_chunkSize) == 0) : true);
        if (!bCheck) {
            ERRLOG("overlapSize is invalid.%lld %lld %lld %lld %lld", startOffset, overlapSize, standaloneOffset,
                standaloneSize, endOffset);
            return false;
        }
    }
    return true;
}

int32_t OceanStorVolumeHandler::GetDirtyRangesFragmentForLunImp(const DirtyRangesRequest& dirtyRangesRequest,
    DirtyRanges& dirtyRanges, std::string& errorDes)
{
    if (dirtyRangesRequest.m_preChangeObj.m_isFullBackup) {
        dirtyRanges.UseFull();
    }
    // 重叠部分
    if (dirtyRangesRequest.m_overlapSize > 0) {
        INFOLOG("Get overlap ranges:%lld", dirtyRangesRequest.m_overlapSize);
        DirtyRangesCalculateInfo calculateInfo;
        calculateInfo.changeID = dirtyRangesRequest.m_curChangeObj.m_id;
        calculateInfo.preChangeID = dirtyRangesRequest.m_preChangeObj.m_id;
        calculateInfo.currentOffset = dirtyRangesRequest.m_startOffset;
        calculateInfo.endOffset = dirtyRangesRequest.m_startOffset + dirtyRangesRequest.m_overlapSize;
        while (calculateInfo.currentOffset < calculateInfo.endOffset) {
            if (CalculateDirtyRanges(calculateInfo, dirtyRanges, errorDes) != Module::SUCCESS) {
                ERRLOG("Failed to calculate unshared dirty ranges.");
                return Module::FAILED;
            }
        }
    }
    // 独立部分
    if (dirtyRangesRequest.m_standaloneSize > 0) {
        INFOLOG("Get standalone ranges:%lld", dirtyRangesRequest.m_standaloneSize);
        DirtyRangesCalculateInfo calculateInfo;
        calculateInfo.changeID = dirtyRangesRequest.m_curChangeObj.m_id;
        calculateInfo.preChangeID = "";
        calculateInfo.currentOffset = dirtyRangesRequest.m_standaloneOffset;
        calculateInfo.endOffset = dirtyRangesRequest.m_standaloneOffset + dirtyRangesRequest.m_standaloneSize;
        while (calculateInfo.currentOffset < calculateInfo.endOffset) {
            if (CalculateDirtyRanges(calculateInfo, dirtyRanges, errorDes) != Module::SUCCESS) {
                ERRLOG("Failed to calculate alloc dirty ranges.");
                return Module::FAILED;
            }
        }
    }
    INFOLOG("Get all ranges finished, id:%s", dirtyRangesRequest.m_curChangeObj.m_id.c_str());
    return Module::SUCCESS;
}

int32_t OceanStorVolumeHandler::CalculateDirtyRanges(DirtyRangesCalculateInfo &calculateInfo, DirtyRanges &dirtyRanges,
    std::string &errorDes)
{
    int32_t iRet = Module::FAILED;
    if (m_chunkSize == 0) {
        ERRLOG("Chunk size value error, %lld", m_chunkSize);
        return iRet;
    }
    uint64_t reqSize = BITMAP_REQ_SIZE * m_chunkSize;
    if (calculateInfo.currentOffset + reqSize > calculateInfo.endOffset) {
        reqSize = calculateInfo.endOffset - calculateInfo.currentOffset;
    }
    DiffBitmap subDiffBitmap;
    subDiffBitmap.m_offset = calculateInfo.currentOffset;
    subDiffBitmap.m_size = reqSize;
    subDiffBitmap.m_chunkSize = m_chunkSize;
    DBGLOG("changeID id: %s,preChangeID id: %s,start offset: %lld,end offset: %lld,chunk size: %lld,data size: %lld",
        calculateInfo.changeID.c_str(), calculateInfo.preChangeID.c_str(), calculateInfo.currentOffset,
        calculateInfo.endOffset, m_chunkSize, reqSize);
    if (calculateInfo.preChangeID.empty() || calculateInfo.preChangeID == FULL_BACKUP) {
        DBGLOG("Start to get alloc bitmap.");
        iRet = m_spApiOperator->GetLunAllocBitmap(calculateInfo.changeID, subDiffBitmap, errorDes);
    } else {
        DBGLOG("Start to get unshared bitmap.");
        iRet = m_spApiOperator->GetLunUnsharedBitmap(calculateInfo.changeID, calculateInfo.preChangeID, subDiffBitmap,
            errorDes);
    }
    if (iRet != Module::SUCCESS) {
        ERRLOG("Get diff bitmap failed, ret:%d errorDes:%s", iRet, errorDes.c_str());
        return iRet;
    }
    iRet = ParseBitmap(subDiffBitmap.m_bitmap, dirtyRanges, calculateInfo.currentOffset, reqSize);
    if (iRet != Module::SUCCESS) {
        errorDes = "Parse bitmap failed.";
        ERRLOG("Parse bitmap failed, %lld", subDiffBitmap.m_offset);
        return iRet;
    }
    calculateInfo.currentOffset = calculateInfo.currentOffset + reqSize;
    return iRet;
}

int32_t OceanStorVolumeHandler::ParseBitmap(std::string &bitmap, DirtyRanges &dirtyRanges, const uint64_t &startOffset,
    const uint64_t &size)
{
    uint64_t chunks = (size + m_chunkSize - 1) / m_chunkSize;
    uint64_t endOffset = startOffset + size;
    if (bitmap.size() % BITMAP_SPLIT != 0) {
        ERRLOG("Device return bitmap format error.");
        return Module::FAILED;
    }
    if (chunks > (bitmap.size() / BITMAP_SPLIT) * BITMAP_BY_BYTE) {
        ERRLOG("Bitmap length is not enough. Chunk number is %lld, bitmap is %s", chunks, bitmap.c_str());
        return Module::FAILED;
    }
    for (std::string::size_type i = 0; i < bitmap.size() / BITMAP_SPLIT; ++i) {
        std::stringstream ss;
        uint32_t c = 0;
        ss << bitmap.substr(BITMAP_SPLIT * i, BITMAP_SPLIT);
        ss >> std::hex >> c;
        uint64_t offset = startOffset + (i * BITMAP_BY_BYTE) * m_chunkSize;
        if (!ParseBitMapByByte(c, m_chunkSize, offset, endOffset, dirtyRanges)) {
            ERRLOG("Parse bit map by byte failed.");
            return Module::FAILED;
        }
    }
    return Module::SUCCESS;
}

int32_t OceanStorVolumeHandler::QueryStoragePoolUsedRate(double &usedCapacityRate)
{
    if (m_spApiOperator->QueryStoragePoolUsedRate(usedCapacityRate) != SUCCESS) {
        ERRLOG("Oceanstor storage query storage pool used rate failed.");
        return FAILED;
    }
    INFOLOG("Oceanstor storage query storage pool used rate success.");
    return SUCCESS;
}

bool OceanStorVolumeHandler::ParseBitMapByByte(const unsigned char &ch, const uint64_t &chunkSize,
    const uint64_t &offSet, const uint64_t &totalSize, DirtyRanges &dirtyRanges)
{
    for (uint32_t bitindex = 0; bitindex < BITMAP_BY_BYTE; ++bitindex) {
        if ((offSet + bitindex * chunkSize) >= totalSize) {
            return true;
        }
        if ((ch & (1 << bitindex)) == 0) {
            continue;
        }
        bool retVal = false ;
        if ((offSet + (bitindex + 1) * chunkSize) <= totalSize) {
            retVal = dirtyRanges.AddRange(DirtyRange(offSet + bitindex * chunkSize, chunkSize));
        } else {
            retVal = dirtyRanges.AddRange(DirtyRange(offSet + bitindex * chunkSize,
                                                     totalSize - (offSet + bitindex * chunkSize)));
        }
        if (!retVal) {
            ERRLOG("AddRange failed.");
            return false;
        }
    }
    return true;
}

int32_t OceanStorVolumeHandler::Flush()
{
    return m_spDeviceFile->Flush() == DISK_DEVICE_OK ? Module::SUCCESS : Module::FAILED;
}
}